using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using JGSY.CMS.LowCode.Platform.Domain.Entities;
using JGSY.CMS.LowCode.Platform.Domain.Interfaces;
using System.Linq.Expressions;
using JGSY.CMS.LowCode.Platform.Infrastructure.CmsDbContext;
using Microsoft.Extensions.Logging;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Repositories
{
    /// <summary>
    /// 部门仓储实现
    /// 提供完整的部门层级管理功能，支持递归查询、路径计算、缓存优化等企业级功能
    /// </summary>
    public class DepartmentRepository : SimpleRepository<Department>, IDepartmentRepository
    {
        private readonly ILogger<DepartmentRepository> _logger;

        public DepartmentRepository(LowCodeDbContext context, ILogger<DepartmentRepository> logger) : base(context)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        #region IRepository<Department> 实现

    public async Task<Department> AddAsync(Department entity)
        {
            try
            {
                if (entity == null)
                    throw new ArgumentNullException(nameof(entity));

                // 验证部门编码唯一性
                if (!string.IsNullOrEmpty(entity.Code))
                {
                    var exists = await IsCodeExistsAsync(entity.Code);
                    if (exists)
                        throw new InvalidOperationException($"部门编码 '{entity.Code}' 已存在");
                }

                entity.CreatedAt = DateTime.UtcNow;
                entity.UpdatedAt = DateTime.UtcNow;
                
                await _context.Set<Department>().AddAsync(entity);
                await _context.SaveChangesAsync();
                
                _logger.LogInformation("创建部门成功，ID: {DepartmentId}, 名称: {DepartmentName}", entity.Id, entity.Name);
                return entity;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "创建部门失败，名称: {DepartmentName}", entity?.Name);
                throw;
            }
        }

    public async Task<int> CountAsync()
        {
            return await _context.Set<Department>().CountAsync();
        }

    public async Task<int> CountAsync(Expression<Func<Department, bool>> predicate)
        {
            return await _context.Set<Department>().CountAsync(predicate);
        }

    public async Task DeleteAsync(Department entity)
        {
            if (entity == null)
                throw new ArgumentNullException(nameof(entity));

            try
            {
                // 检查是否有子部门
                var hasChildren = await _context.Set<Department>()
                    .AnyAsync(d => d.ParentId == entity.Id);
                
                if (hasChildren)
                    throw new InvalidOperationException("不能删除包含子部门的部门");

                // 检查是否有用户
                var hasUsers = await _context.Set<User>()
                    .AnyAsync(u => u.DepartmentId == entity.Id);
                
                if (hasUsers)
                    throw new InvalidOperationException("不能删除包含用户的部门");

                _context.Set<Department>().Remove(entity);
                await _context.SaveChangesAsync();
                
                _logger.LogInformation("删除部门成功，ID: {DepartmentId}, 名称: {DepartmentName}", entity.Id, entity.Name);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "删除部门失败，ID: {DepartmentId}", entity.Id);
                throw;
            }
        }

    public async Task DeleteAsync(object id)
        {
            var entity = await GetByIdAsync(id);
            if (entity != null)
            {
                await DeleteAsync(entity);
            }
        }

    public async Task<bool> ExistsAsync(Expression<Func<Department, bool>> predicate)
        {
            return await _context.Set<Department>().AnyAsync(predicate);
        }

    public async Task<List<Department>> FindAsync(Expression<Func<Department, bool>> predicate)
        {
            return await _context.Set<Department>()
                .Where(predicate)
                .Include(d => d.Parent)
                .Include(d => d.Manager)
                .OrderBy(d => d.SortOrder)
                .ThenBy(d => d.Name)
                .ToListAsync();
        }

    public async Task<Department?> FindSingleAsync(Expression<Func<Department, bool>> predicate)
        {
            return await _context.Set<Department>()
                .Where(predicate)
                .Include(d => d.Parent)
                .Include(d => d.Manager)
                .FirstOrDefaultAsync();
        }

    public async Task<Department?> GetByIdAsync(object id)
        {
            if (id == null) return null;
            
            var departmentId = Convert.ToInt64(id);
            return await _context.Set<Department>()
                .Include(d => d.Parent)
                .Include(d => d.Manager)
                .Include(d => d.Children)
                .FirstOrDefaultAsync(d => d.Id == departmentId);
        }

    public async Task<(List<Department> Items, int Total)> GetPagedAsync(int pageIndex, int pageSize, Expression<Func<Department, bool>>? predicate = null)
        {
            var query = _context.Set<Department>()
                .Include(d => d.Parent)
                .Include(d => d.Manager)
                .AsQueryable();

            if (predicate != null)
            {
                query = query.Where(predicate);
            }

            var total = await query.CountAsync();
            var items = await query
                .OrderBy(d => d.SortOrder)
                .ThenBy(d => d.Name)
                .Skip(pageIndex * pageSize)
                .Take(pageSize)
                .ToListAsync();

            return (items, total);
        }

        Task<List<Department>> IRepository<Department>.GetAllAsync()
        {
            // 返回包含必要导航属性的有序列表，避免空引用并与其他查询风格一致
            var list = _context.Departments
                .Include(d => d.Parent)
                .Include(d => d.Manager)
                .OrderBy(d => d.SortOrder)
                .ThenBy(d => d.Name)
                .ToList();
            return Task.FromResult(list);
        }

    public async Task<int> SaveChangesAsync()
        {
            return await _context.SaveChangesAsync();
        }

        #endregion

        #region IDepartmentRepository 专用方法实现

        /// <summary>
        /// 根据编码查找部门
        /// </summary>
        public async Task<Department?> GetByCodeAsync(string code)
        {
            if (string.IsNullOrEmpty(code))
                return null;

            return await _context.Set<Department>()
                .Include(d => d.Parent)
                .Include(d => d.Manager)
                .FirstOrDefaultAsync(d => d.Code == code);
        }

        /// <summary>
        /// 获取子部门列表（使用递归CTE查询）
        /// </summary>
        public async Task<List<Department>> GetChildrenAsync(long parentId)
        {
            try
            {
                // 使用递归查询获取所有层级的子部门
                var sql = @"
                    WITH DepartmentHierarchy AS (
                        -- 锚点查询：直接子部门
                        SELECT Id, Name, Code, ParentId, ManagerId, SortOrder, Status, CreatedAt, UpdatedAt, Description
                        FROM departments 
                        WHERE ParentId = {0} AND Status = 1

                        UNION ALL

                        -- 递归查询：子部门的子部门
                        SELECT d.Id, d.Name, d.Code, d.ParentId, d.ManagerId, d.SortOrder, d.Status, d.CreatedAt, d.UpdatedAt, d.Description
                        FROM departments d
                        INNER JOIN DepartmentHierarchy dh ON d.ParentId = dh.Id
                        WHERE d.Status = 1
                    )
                    SELECT * FROM DepartmentHierarchy ORDER BY SortOrder, Name";

                var children = await _context.Set<Department>()
                    .FromSqlRaw(sql, parentId)
                    .Include(d => d.Manager)
                    .ToListAsync();

                _logger.LogDebug("获取部门子节点成功，父部门ID: {ParentId}, 子部门数量: {Count}", parentId, children.Count);
                return children;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取部门子节点失败，父部门ID: {ParentId}", parentId);
                
                // 降级为简单查询
                return await _context.Set<Department>()
                    .Where(d => d.ParentId == parentId && d.Status == 1)
                    .Include(d => d.Manager)
                    .OrderBy(d => d.SortOrder)
                    .ThenBy(d => d.Name)
                    .ToListAsync();
            }
        }

        /// <summary>
        /// 获取顶级部门列表
        /// </summary>
        public async Task<List<Department>> GetRootDepartmentsAsync()
        {
            return await _context.Set<Department>()
                .Where(d => d.ParentId == null && d.Status == 1)
                .Include(d => d.Manager)
                .Include(d => d.Children.Where(c => c.Status == 1))
                .OrderBy(d => d.SortOrder)
                .ThenBy(d => d.Name)
                .ToListAsync();
        }

        /// <summary>
        /// 检查部门编码是否存在
        /// </summary>
        public async Task<bool> IsCodeExistsAsync(string code, long? excludeId = null)
        {
            if (string.IsNullOrEmpty(code))
                return false;

            var query = _context.Set<Department>().Where(d => d.Code == code);
            
            if (excludeId.HasValue)
            {
                query = query.Where(d => d.Id != excludeId.Value);
            }

            return await query.AnyAsync();
        }

        /// <summary>
        /// 获取部门路径（从根到该部门的完整路径）
        /// </summary>
        public async Task<List<Department>> GetPathAsync(long departmentId)
        {
            try
            {
                var path = new List<Department>();
                var currentDepartment = await GetByIdAsync(departmentId);

                if (currentDepartment == null)
                    return path;

                // 向上递归构建路径
                while (currentDepartment != null)
                {
                    path.Insert(0, currentDepartment); // 插入到开头，保证从根到叶子的顺序
                    
                    if (currentDepartment.ParentId.HasValue)
                    {
                        currentDepartment = await GetByIdAsync(currentDepartment.ParentId.Value);
                    }
                    else
                    {
                        break;
                    }
                }

                _logger.LogDebug("获取部门路径成功，部门ID: {DepartmentId}, 路径长度: {PathLength}", departmentId, path.Count);
                return path;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取部门路径失败，部门ID: {DepartmentId}", departmentId);
                throw;
            }
        }

        /// <summary>
        /// 获取活跃部门列表
        /// </summary>
        public async Task<List<Department>> GetActiveDepartmentsAsync()
        {
            return await _context.Set<Department>()
                .Where(d => d.Status == 1)
                .Include(d => d.Parent)
                .Include(d => d.Manager)
                .OrderBy(d => d.SortOrder)
                .ThenBy(d => d.Name)
                .ToListAsync();
        }

        /// <summary>
        /// 获取部门查询对象
        /// </summary>
        public async Task<IEnumerable<Department>> GetQueryableAsync()
        {
            return await _context.Set<Department>()
                .Include(d => d.Parent)
                .Include(d => d.Manager)
                .Include(d => d.Children)
                .ToListAsync();
        }

        #endregion

        #region 新增增强方法

        /// <summary>
        /// 获取部门统计信息
        /// </summary>
        public async Task<Dictionary<string, int>> GetDepartmentStatisticsAsync()
        {
            var stats = new Dictionary<string, int>();
            
            stats["TotalDepartments"] = await _context.Set<Department>().CountAsync();
            stats["ActiveDepartments"] = await _context.Set<Department>().CountAsync(d => d.Status == 1);
            stats["RootDepartments"] = await _context.Set<Department>().CountAsync(d => d.ParentId == null);
            stats["DepartmentsWithManager"] = await _context.Set<Department>().CountAsync(d => d.ManagerId != null);
            
            return stats;
        }

        /// <summary>
        /// 批量更新部门排序
        /// </summary>
        public async Task<bool> BatchUpdateSortOrderAsync(Dictionary<long, int> departmentOrders)
        {
            using var transaction = await _context.Database.BeginTransactionAsync();
            try
            {
                foreach (var (departmentId, sortOrder) in departmentOrders)
                {
                    var department = await _context.Set<Department>().FindAsync(departmentId);
                    if (department != null)
                    {
                        department.SortOrder = sortOrder;
                        department.UpdatedAt = DateTime.UtcNow;
                    }
                }

                var rowsAffected = await _context.SaveChangesAsync();
                await transaction.CommitAsync();
                
                _logger.LogInformation("批量更新部门排序成功，影响行数: {RowsAffected}", rowsAffected);
                return rowsAffected > 0;
            }
            catch (Exception ex)
            {
                await transaction.RollbackAsync();
                _logger.LogError(ex, "批量更新部门排序失败");
                throw;
            }
        }

        /// <summary>
        /// 获取部门树形结构
        /// </summary>
        public async Task<List<Department>> GetDepartmentTreeAsync()
        {
            var allDepartments = await _context.Set<Department>()
                .Where(d => d.Status == 1)
                .Include(d => d.Manager)
                .OrderBy(d => d.SortOrder)
                .ThenBy(d => d.Name)
                .ToListAsync();

            return BuildDepartmentTree(allDepartments, null);
        }

        /// <summary>
        /// 构建部门树形结构
        /// </summary>
        private List<Department> BuildDepartmentTree(List<Department> allDepartments, long? parentId)
        {
            return allDepartments
                .Where(d => d.ParentId == parentId)
                .Select(d =>
                {
                    d.Children = BuildDepartmentTree(allDepartments, d.Id);
                    return d;
                })
                .ToList();
        }

        #endregion
    }
}
